iT邦幫忙

0

Javascript 進階 6-2 原型在哪裡?

  • 分享至 

  • xImage
  •  

這篇文章主要是要來介紹原型

https://ithelp.ithome.com.tw/upload/images/20200226/20121770fHj3BorEHM.png

在介紹原型之前,我們要先來複習物件的內容

https://ithelp.ithome.com.tw/upload/images/20200226/20121770rNNng1Ersf.png

當我們要定義一隻狗的時候,我們會利用物件的資料結構,來對這隻狗進行描述。

例如它的顏色、體型大小,以及可以吠叫的方法。

主要的原因就是因為 JS 基本上都是由物件的方法去構成資料。

而原型呢也是一樣的概念喔!

在前一篇文章,類別繼承中我們有提到,如果我們要定義一個像是這樣的內容,我們會使用 class 來定義它。

但是 JS 中都是使用物件來定義,所以我們在定義原型的時候也是使用物件的方式來定義。

https://ithelp.ithome.com.tw/upload/images/20200226/20121770PxzRansiaA.png

如果狗要透過這個原型來建立實體的話,也是透過繼承的方式繼承了原型的屬性跟方法,因此這就是兩個物件的概念。

原型的狗就會有顏色、體型大小,以及可以吠叫的方法。而在實體的狗呢這些屬性就會有可以自定義的空間。

那麼吠叫的部分就可以繼承原本原型的方法。

https://ithelp.ithome.com.tw/upload/images/20200226/20121770puIpGxnGFX.png

實際上,當我們運行JS的時候,新增一個物件的實體的時候就會有屬於該實體的屬性

那麼原型的部分依樣也會有它自己的屬性,那這樣的結構上依然是屬於兩個物件。

另外,除了實體可以繼承一個原型之外,原型也可以繼承另外一個原型喔!

那麼在另外一個原型的部分也可以擁有自己的屬性以及方法,那麼這樣的繼承關係可以一段一段的向上繼承,這樣的繼承狀態我們又稱為原型鏈

再來,這個實體我們要取用其中的屬性的時候,會使用點運算子的方法進行取用,例如 obj.Prop1obj.Prop2

而當我們要取用的屬性或是方法沒有在這個實體上的時候,就會透過原型鏈向上查找,直到找到這個原型鏈的頂端為止。

https://ithelp.ithome.com.tw/upload/images/20200226/20121770BInTODyBVU.png

除此之外呢,原型還有另一個特色,就是

如果用同一個原型新增了兩個實體,這兩個實體就會共用同一個原型繼承,共用相同的屬性名稱以及相同的方法。

https://ithelp.ithome.com.tw/upload/images/20200226/20121770hLjVEZdD0P.png

接下來總結一下觀念:

https://ithelp.ithome.com.tw/upload/images/20200226/20121770a3QGohidQC.png

那麼我們再來就透過程式碼的運作來進行剛剛上面的觀念驗證吧!

var a = [1, 2, 3];
console.log(a);

執行之後我們把這個陣列打開來看

https://ithelp.ithome.com.tw/upload/images/20200226/20121770IcwIW3UsIS.png

可以看到裡面有對應 0 1 2的屬性,因為我們知道陣列的本質其實也是物件,所以這裡的 0 1 2其實也是這個陣列的物件屬性。當然 length 也是。

所以物件的屬性的話我們有兩種取值的方式,一個是 [] 一個是 .

https://ithelp.ithome.com.tw/upload/images/20200226/20121770rrMkfctgOo.png

那麼這個陣列現在是屬於一個實體,我們可以透過 proto 的屬性 來看看它陣列的原型

https://ithelp.ithome.com.tw/upload/images/20200226/20121770fOGQaKn1dw.png

可以看到陣列的原型中有許多的方法,那麼我們剛剛也提到可以透過點運算子取用他的方法。

那麼這邊我們選用的是 forEach 的方法,透過這個方法可以將陣列的每個值都遍歷過一遍。

https://ithelp.ithome.com.tw/upload/images/20200226/20121770JcyCBtCoUg.png

那麼這個 forEach 就不是屬於 a 這個實體的方法,而是屬於陣列原型的屬性方法。

還有我們剛剛也有講到原型是共用的,所以我們再來新增 b 這個新的陣列 為 [4, 5 , 6]

我們剛剛也有提到 proto 的屬性是指向陣列的原型,所以我們照理說也可以用 proto 的屬性新增方法到陣列的原型上,讓 b 陣列也可以取用到相同的方法。

PS: proto 的屬性雖然可以達成一樣的效果,但一般我們還是不建議這樣使用,後面的章節會教大家使用 prototype 的屬性將要新增的 function 掛載到原型上,讓其他實體也可以取用到。

那麼這邊我們把陣列最後一個值取出來的方法透過 proto 的屬性掛載到陣列的原型上。

https://ithelp.ithome.com.tw/upload/images/20200226/20121770E7szaPA7p8.png

https://ithelp.ithome.com.tw/upload/images/20200226/20121770789NXfNtlR.png

另外我們就真的實用這個 getLast 的方法看是否有成功

https://ithelp.ithome.com.tw/upload/images/20200226/20121770DMqSlsreM4.png

很明顯就成功的印出我們想要的內容。

討論一下原型的層級問題吧!

我們剛剛說到,打開a 或 b 的 proto 的屬性能夠找到陣列的原型。

那麼繼續往下找又可以找到另一個 proto 的屬性,再把它打開以後會看到的是物件的原型。

因此這個陣列的原型其實是繼承了物件的原型。

而繼續往下看就可以看到物件的一些方法,但到最底就沒有 proto 的屬性,代表說這個物件的原型就是原型鏈的最頂層了!

好,我們再來看一些code。

https://ithelp.ithome.com.tw/upload/images/20200226/20121770SiNkPYAm9x.png

我們新增了一個新的物件,並且對該物件的物件原型上掛載 getName 的方法,而之後打開 a 跟 b 的原型鏈最頂端的物件原型,也可以找到 getName 的方法的方法喔!

https://ithelp.ithome.com.tw/upload/images/20200226/20121770ER7qvIdIjg.png

那麼接下來我們就試著在陣列中使用這個 getName 的方法。

首先我們先對 b 這個陣列加入了 name 的屬性,之後我們預期用 getName 應該可以抓到我們剛剛設定的 name 的內容

https://ithelp.ithome.com.tw/upload/images/20200226/201217703VzUTQBrj9.png

果不其然成功了,但陣列上並沒有 getName 的方法,所以透過向上查找的方式,在物件的原型上找到了 getName 的方法並且使用它。

那麼這篇文章就介紹了原型以及原型鏈的概念以及實作。

如果沒有問題的話就繼續往下巴~!汪汪


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言